<script>
export default {
  name: 'CountUp'
}
</script>
<script setup>
import { onMounted, onUnmounted, ref, watch, nextTick } from 'vue'
import { CountUp } from 'countup.js'

const props = defineProps({
  // 结束数值
  endVal: {
    type: [Number, String],
    required: true
  },
  // 开始数值
  startVal: {
    type: [Number, String],
    default: 0
  },
  // 动画时长，单位 s
  duration: {
    type: [Number, String],
    default: 2.5
  },
  // 是否自动计数
  autoplay: {
    type: Boolean,
    default: true
  },
  // 循环次数，有限次数 / 无限循环
  loop: {
    type: [Boolean, Number, String],
    default: false
  },
  // 延时，单位 s
  delay: {
    type: Number,
    default: 0
  },
  // countup 配置项
  options: {
    type: Object,
    default: () => ({})
  }
})

const emits = defineEmits(['init', 'finished'])

const elRef = ref(null)
const countUp = ref(null)

const initCountUp = () => {
  console.log('CountUp initCountUp called, props:', props)
  nextTick(() => {
    console.log('CountUp nextTick, elRef.value:', elRef.value)
    if (!elRef.value) {
      console.error('CountUp: elRef is null')
      return
    }
    const startVal = Number(props.startVal)
    const endVal = Number(props.endVal)
    const duration = Number(props.duration)
    console.log('CountUp init values:', { startVal, endVal, duration })
    try {
      countUp.value = new CountUp(elRef.value, endVal, {
        startVal,
        duration,
        ...props.options
      })
      if (countUp.value.error) {
        console.error('CountUp error:', countUp.value.error)
        return
      }
      console.log('CountUp initialized successfully')
      emits('init', countUp.value)
      
      // 初始化成功后，如果 autoplay 为 true，立即启动动画
      if (props.autoplay) {
        console.log('CountUp autoplay is true, starting animation')
        loopAnim()
      }
    } catch (error) {
      console.error('CountUp initialization exception:', error)
    }
  })
}

const startAnim = (cb) => {
  console.log('CountUp startAnim called, countUp.value:', countUp.value)
  if (countUp.value) {
    countUp.value.start(cb)
  }
}

// endVal change & autoplay: true, restart animate
watch(
  () => props.endVal,
  (value) => {
    if (props.autoplay && countUp.value) {
      countUp.value.update(value)
    }
  }
)

// loop animation
const finished = ref(false)
let loopCount = 0
const loopAnim = () => {
  console.log('CountUp loopAnim called, loopCount:', loopCount)
  loopCount++
  startAnim(() => {
    const isTruely = typeof props.loop === 'boolean' && props.loop
    if (isTruely || props.loop > loopCount) {
      delay(() => {
        if (countUp.value) {
          countUp.value.reset()
        }
        loopAnim()
      }, props.delay)
    } else {
      finished.value = true
    }
  })
}
watch(finished, (flag) => {
  if (flag) {
    emits('finished')
  }
})

onMounted(() => {
  initCountUp()
})
onUnmounted(() => {
  cancelAnimationFrame(dalayRafId)
  if (countUp.value) {
    countUp.value.reset()
  }
})

let dalayRafId
// delay to execute callback function
const delay = (cb, seconds = 1) => {
  let startTime
  function count(timestamp) {
    if (!startTime) startTime = timestamp
    const diff = timestamp - startTime
    if (diff < seconds * 1000) {
      dalayRafId = requestAnimationFrame(count)
    } else {
      cb()
    }
  }
  dalayRafId = requestAnimationFrame(count)
}

const restart = () => {
  initCountUp()
  startAnim()
}

defineExpose({
  init: initCountUp,
  restart
})
</script>

<template>
  <view class="countup-wrap">
    <slot name="prefix"></slot>
    <span ref="elRef" class="countup-number">0</span>
    <slot name="suffix"></slot>
  </view>
</template>

<style scoped lang="scss">
.countup-wrap {
  display: inline-flex;
  align-items: center;
  
  .countup-number {
    display: inline-block;
    font-variant-numeric: tabular-nums;
  }
}
</style>
